from django.contrib import auth
from django.contrib.auth.hashers import make_password
from django.db import models
from django.contrib.auth.models import User, AbstractBaseUser, PermissionsMixin, BaseUserManager
from shortuuidfield import ShortUUIDField

# 用户状态
class UserStatusChoices(models.IntegerChoices):
    ACTIVE = 1          # 已经激活的
    UNACTIVE = 2        # 未激活的
    LOCKED = 3           # 锁定的


# 用户身份
class UserTypeChoices(models.IntegerChoices):
    ADMIN = 1          # 后台管理员
    VIP_CUSTOMER = 2   # VIP客户
    CUSTOMER = 3       # 普通客户

class BackUserManager(BaseUserManager):
    use_in_migrations = True                # 告诉Django，这个类是一个管理器，保证迁移时管理器不会触发复杂的字段校验逻辑。

    def _create_user_object(self, realname, email, password, **extra_fields):
        """
        创建普通用户和超级用户的时候，有一些代码会复用，这个是把复用的代码抽离出来
        """
        if not realname:
            raise ValueError("必须设置真实姓名！")
        email = self.normalize_email(email)             # 给邮箱设置标准化
        user = self.model(realname=realname, email=email, **extra_fields)       # 创建用户对象
        user.password = make_password(password)                                 # 给密码设置加密
        return user

    def _create_user(self, realname, email, password, **extra_fields):
        """
        同步方法，在创建用户的时候把用户信息保存到数据库
        """
        user = self._create_user_object(realname, email, password, **extra_fields)
        user.save(using=self._db)
        return user

    async def _acreate_user(self, realname, email, password, **extra_fields):
        """
        异步方法，在创建用户的时候把用户信息保存到数据库
        """
        user = self._create_user_object(realname, email, password, **extra_fields)
        await user.asave(using=self._db)
        return user

    def create_user(self, realname, email=None, password=None, **extra_fields):
        """
        同步方法，创建普通用户的具体逻辑
        """
        extra_fields.setdefault("is_staff", False)           # 创建用户时，是否将该用户设置为员工，这里是否
        extra_fields.setdefault("user_type", UserTypeChoices.CUSTOMER)     # 创建用户时，用户身份默认为普通用户
        extra_fields.setdefault("is_superuser", False)
        return self._create_user(realname, email, password, **extra_fields)

    create_user.alters_data = True              # 告诉Django，这个方法会修改数据库，所以需要设置这个属性为True，保证用户创建操作不会被缓存。

    async def acreate_user(self, realname, email=None, password=None, **extra_fields):
        """
        异步创建普通用户的具体逻辑
        """
        extra_fields.setdefault("is_staff", False)           #  创建用户时，是否将该用户设置为员工，这里是否
        extra_fields.setdefault("user_type", UserTypeChoices.CUSTOMER)  # 创建用户时，用户身份默认为普通用户
        extra_fields.setdefault("is_superuser", False)
        return await self._acreate_user(realname, email, password, **extra_fields)

    acreate_user.alters_data = True


    """
    下面的是创建超级管理员的逻辑相关
    """

    def create_superuser(self, realname, email=None, password=None, **extra_fields):

        """
        同步创建超级管理员
        """

        extra_fields.setdefault("is_staff", True)                       # 创建用户时，管理员设置为员工
        extra_fields.setdefault("user_type", UserTypeChoices.ADMIN)  # 创建管理员时，用户身份默认为后台管理员
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("status", UserStatusChoices.ACTIVE)     # 创建超级管理员的时候，是激活的

        if extra_fields.get("is_staff") is not True:
            raise ValueError("超级用户必须设置is_staff=True")
        if extra_fields.get("is_superuser") is not True:
            raise ValueError("超级用户必须设置is_superuser=True")

        return self._create_user(realname, email, password, **extra_fields)

    create_superuser.alters_data = True

    async def acreate_superuser(
        self, realname, email=None, password=None, **extra_fields
    ):

        """
        异步创建超级管理员
        """
        extra_fields.setdefault("is_staff", True)                       # 创建用户时，管理员设置为员工
        extra_fields.setdefault("user_type", UserTypeChoices.ADMIN)  # 创建管理员时，用户身份默认为后台管理员
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("status", UserStatusChoices.ACTIVE)     # 创建超级管理员的时候，是激活的

        if extra_fields.get("is_staff") is not True:
            raise ValueError("超级用户必须设置is_staff=True")
        if extra_fields.get("is_superuser") is not True:
            raise ValueError("超级用户必须设置is_superuser=True")

        return await self._acreate_user(realname, email, password, **extra_fields)

    acreate_superuser.alters_data = True

    def with_perm(
        self, perm, is_active=True, include_superusers=True, backend=None, obj=None
    ):
        if backend is None:
            backends = auth._get_backends(return_tuples=True)
            if len(backends) == 1:
                backend, _ = backends[0]
            else:
                raise ValueError(
                    "You have multiple authentication backends configured and "
                    "therefore must provide the `backend` argument."
                )
        elif not isinstance(backend, str):
            raise TypeError(
                "backend must be a dotted import path string (got %r)." % backend
            )
        else:
            backend = auth.load_backend(backend)
        if hasattr(backend, "with_perm"):
            return backend.with_perm(
                perm,
                is_active=is_active,
                include_superusers=include_superusers,
                obj=obj,
            )
        return self.none()


# 重写用户模型
class BackUser(AbstractBaseUser, PermissionsMixin):
    """
    自定义的user模型
    """
    uid = ShortUUIDField(primary_key= True)                             # 自定义的uid，使用ShortUUIDField，作为用户的主键
    realname = models.CharField(max_length=150,unique=False)            # 真实姓名
    email = models.EmailField(unique=True, blank=False)                 # 邮箱，唯一，不允许为空
    telephone = models.CharField(max_length=20, blank=True)             # 手机号，允许为空
    is_staff = models.BooleanField(default=False)                        # 是否是员工，默认为False
    is_active = models.BooleanField(default=True)                       # 是否激活，默认为True
    status = models.IntegerField(choices=UserStatusChoices, default=UserStatusChoices.UNACTIVE)     # 用户状态，默认为未激活
        # 说明：我们自己写的staus，在逻辑上已经实现了is_active字段的功能，但是为了方便，还是保留了is_active字段，因为删除掉is_active这个字段系统会报错
    user_type = models.IntegerField(choices=UserTypeChoices, default=UserTypeChoices.CUSTOMER)  # 用户身份类型
    date_joined = models.DateTimeField(auto_now_add=True)               # 创建时间


    objects = BackUserManager()           # user的管理器，主要用于控制创建用户

    EMAIL_FIELD = "email"           # 指定用户的哪个字作为邮箱字段
    # USERNAME_FIELD是用来鉴权的，可以理解为指定哪个字段用作用户身份的唯一凭证
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["realname", "password"]     # 创建用户时，需要提供哪些字段，但是不能重复包含USERNAME_FIELD和EMAIL_FIELD已经设置过的字段
    # 这样设置完成之后，在创建用户的时候，email、realname和password三个字段是必传的


    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def get_full_name(self):
        """
        拼接first_name和last_name的，但是我们去掉了这两个字段，直接返回realname
        """
        return self.realname
    def get_short_name(self):
        return self.realname


